// netlib.h

#ifndef _KS_INC_NETLIB_H_
#define _KS_INC_NETLIB_H_

#include "netlib_base.h"
#include "message_base.h"

// event based async network library
//
// KSNetEventDispatcher: event dispatcher for
// {
//   KSNetListener     & KSNetListenerSink       // socket listener & it's event sink
//   KSNetChannel      & KSNetChannelSink        // socket channel & it's event sink
//   KSNetMessageQueue & KSNetMessageQueueNotify // message queue & it's on_messages notifier
// }
//

KS_DECLS_BEGIN

#ifdef _WIN32
	typedef struct _KSIOCPOperator		KSIOCPOperator;
	typedef struct _KSListenOperator	KSListenOperator;
	typedef struct _KSChannelOperator	KSChannelOperator;
	typedef void (*KSIOCPNotify)(KSIOCPOperator* op, DWORD transferred, void* key, int err);

	struct _KSIOCPOperator {
		OVERLAPPED		ov;
		KSIOCPNotify	notify;
	};

	struct _KSListenOperator {
		KSIOCPOperator	parent;
		SOCKET			new_fd;
		char			addr_buf[ (sizeof(SOCKADDR_IN) + 16) * 2 ];
	};

	struct _KSChannelOperator {
		KSIOCPOperator	parent;
		BOOL			busy;
	};

#else
	typedef struct _KSEpollNotifer	KSEpollNotifer;

	struct _KSEpollNotifer {
		void (*cb_notify)(KSEpollNotifer* notifier, uint32_t events);
		KSEpollNotifer*	async_event_next;
	};

#endif

// net service, dispatch network events
//  1. use IOCP in win32 and use only support one thread
//  2. use Epoll ET mode in linux
//
typedef struct _KSNetEventDispatcher	KSNetEventDispatcher;

struct _KSNetEventDispatcher {
	#ifdef _WIN32
		HANDLE				__completion_port;

	#else
		int					__epoll_fd;
		int					__fd_num;
		struct epoll_event*	__events;
		KSEpollNotifer*		__async_events;
		KSEpollNotifer		__async_events_end_node;
	#endif

	int						timeout_ms;
};
// initialize self, just create a completion port/or epoll with timeout_ms
BOOL    ks_net_event_dispatcher_init(KSNetEventDispatcher* self, int timeout_ms);
void    ks_net_event_dispatcher_uninit(KSNetEventDispatcher* self);
// use caller thread to queue events(if event occur, then call )
void    ks_net_event_dispatcher_dispatch(KSNetEventDispatcher* self);

// net listener, accept client socket connection and generate cb_accept events
//
typedef struct _KSNetListener		KSNetListener;

typedef void (*KSNetListenerNotify)(KSNetListener* listener, KSSockFD new_fd, struct sockaddr* peer_addr, int peer_len);

struct _KSNetListener {
	#ifdef _WIN32
		int					__op_count;
		KSListenOperator**	__op_accepts;

	#else
		KSEpollNotifer		__parent;
	#endif

	KSSockFD				fd;
	KSNetListenerNotify		notify;

	struct sockaddr			addr;		// real listen addr
	struct sockaddr			bind_addr;	// bind addr, maybe 0.0.0.0:0
	int						listen_count;
	BOOL					reuse_addr;
};

// initialize self, just fill some data field, no bind/listen api call
BOOL    ks_net_listener_create			( KSNetListener* self
										, const struct sockaddr* addr
										, int listen_count
										, KSNetListenerNotify notify );

void    ks_net_listener_destroy			(KSNetListener* self);
BOOL    ks_net_listener_is_working		(KSNetListener* self);
// associate self with dp, then let self starts listen for connection(s)
BOOL    ks_net_listener_start			(KSNetListener* self, KSNetEventDispatcher* dp);
void    ks_net_listener_stop			(KSNetListener* self);

// net channel status
//
typedef enum _KSNetChannelStatus {
	// working status < 0
	KS_NET_CHANNEL_ST_WAIT_PEER_CLOSE		= -3,	// wait peer close
	KS_NET_CHANNEL_ST_CONNECTING			= -2,	// connecting
	KS_NET_CHANNEL_ST_CONNECTED				= -1,	// connected

	// free status == 0
	KS_NET_CHANNEL_ST_FREE					= 0,	// free status, only status can be reuse!!!

	// closed status > 0
	KS_NET_CHANNEL_ST_CLOSED				= 1,	// normal closed
	KS_NET_CHANNEL_ST_CONNECT_FAILED		= 2,	// connect failed
	KS_NET_CHANNEL_ST_CONNECT_FAILED_TIMEOUT= 3,	// connect failed - timeout
	KS_NET_CHANNEL_ST_PEER_SHUTDOWN			= 4,	// peer shutdown
	KS_NET_CHANNEL_ST_SEND_IO_FAILED		= 5,	// send() return -1
	KS_NET_CHANNEL_ST_RECV_IO_FAILED		= 6,	// recv() return -1
	KS_NET_CHANNEL_ST_IO_ERROR				= 7,	// io error
	KS_NET_CHANNEL_ST_SPEED_LIMIT			= 8,	// speed limit
	KS_NET_CHANNEL_ST_BAD_PACKET_SIZE		= 9,	// parse size return 0 error
	KS_NET_CHANNEL_ST_ERROR_REVERSED_0		= 10,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR_REVERSED_1		= 11,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR_REVERSED_2		= 12,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR_REVERSED_3		= 13,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR_REVERSED_4		= 14,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR_REVERSED_5		= 15,	// reversed errors
	KS_NET_CHANNEL_ST_ERROR					= 16,	// other error start status value
	KS_NET_CHANNEL_ST_USER_DEFINED_ERROR			// user defined error first status
} KSNetChannelStatus;

typedef struct _KSNetChannelSink	KSNetChannelSink;
typedef struct _KSNetChannel		KSNetChannel;

// receive_limit_speed : bytes per second, 0 means not use receive speed limit
// receive_limit_delay : check speed limit average time
// for example :
//
//    16KB/s average 5 second - rlimit_speed=16*1024  rlimit_delay=5*1000
//    8KB/s average 15 second - rlimit_speed=8*1024   rlimit_delay=15*1000
//                   no limit - rlimit_speed=0        rlimit_delay=0
//
// TODO : cb_parse_size return size_t replace int, unknown packet size return ~0 or len + 1 or ...
//
struct _KSNetChannelSink {
	void	(*cb_connected)		(KSNetChannel* channel);
	void	(*cb_closed)		(KSNetChannel* channel, int status);
	void	(*cb_flush)			(KSNetChannel* channel);
	int		(*cb_parse_size)	(KSNetChannel* channel, void* buf, size_t len);
	void	(*cb_packet)		(KSNetChannel* channel, void* pkt, size_t len);
	void	(*cb_rlimit_check)	(KSNetChannel* channel, size_t* rlimit_speed, size_t* rlimit_delay);	// set NULL means not check
	void	(*cb_rlimit)		(KSNetChannel* channel, uint32_t speed, uint32_t now);		// set NULL means close when rlimit
};

struct _KSNetChannel {
	#ifdef _WIN32
		KSChannelOperator*		__op_send;
		KSChannelOperator*		__op_recv;

	#else
		KSEpollNotifer			__parent;
		KSNetEventDispatcher*	__dp;
	#endif

	#ifdef KS_DEBUG
		uint32_t				__dbg_type_id;	// used for debug type check
	#endif

	KSSockFD			fd;
	struct sockaddr		sock_addr;
	struct sockaddr		peer_addr;
	int					status;
	int					err;
	KSNetChannelSink*	sink;

	size_t				slen;
	char*				sbuf;
	char*				spos;

	size_t				rlen;
	char*				rbuf;
	char*				rpos;  ///< don't add this member in sink's cb_packet

// private:
	uint32_t			__rlimit_time;
	uint32_t			__rlimit_size;
};

#ifdef KS_DEBUG
	#define __ks_net_channel_dbg_type_id_set(self, id)		((self)->__dbg_type_id |= id)
	#define __ks_net_channel_dbg_type_id_check(self, id)	(((self)->__dbg_type_id & id) != 0)
#else
	#define __ks_net_channel_dbg_type_id_set(self, id)
	#define __ks_net_channel_dbg_type_id_check(self, id)    1
#endif

#define ks_net_channel_is_working(self)			((self)->status < 0)
#define ks_net_channel_sbuf_remain(self)		((self)->slen - ((self)->spos - (self)->sbuf))

#ifdef _WIN32
	#define ks_net_channel_sending_busy(self)	((self)->__op_send->busy != FALSE)
#else
	#define ks_net_channel_sending_busy(self)	((self)->spos != (self)->sbuf)
#endif

BOOL    ks_net_channel_init				(KSNetChannel* self, KSNetChannelSink* sink);
void    ks_net_channel_uninit			(KSNetChannel* self);
BOOL    ks_net_channel_connect_sync		(KSNetChannel* self, KSNetEventDispatcher* dp, const struct sockaddr* addr);
BOOL    ks_net_channel_connect_async	(KSNetChannel* self, KSNetEventDispatcher* dp, const struct sockaddr* addr);
// set self's connection has been made, then register self's event with dp
BOOL    ks_net_channel_connect_finish	(KSNetChannel* self, KSNetEventDispatcher* dp, KSSockFD fd);
BOOL    ks_net_channel_write_all_full	(KSNetChannel* self, const void* buf, size_t len, const void* header_buf, size_t header_len);
size_t  ks_net_channel_write			(KSNetChannel* self, const void* buf, size_t len);
void    ks_net_channel_flush			(KSNetChannel* self);
void    ks_net_channel_close_full		(KSNetChannel* self, int status, int err);

#define	ks_net_channel_close(self, status)		ks_net_channel_close_full((self), (status), __LINE__)

#define	ks_net_channel_write_all(self, buf, len) \
			ks_net_channel_write_all_full((self), (buf), (len), 0, 0)

#define	ks_net_channel_close_wait_peer(self) \
			ks_net_channel_close((self), KS_NET_CHANNEL_ST_WAIT_PEER_CLOSE)

const char*	ks_net_channel_fetch_status_desc		(int status);


typedef struct _KSNetSingal		KSNetSingal;
typedef void (*KSNetSingalNotify)(void* tag);

struct _KSNetSingal {
	#ifdef _WIN32
		KSIOCPOperator*		__notify_op;
	#else
		KSEpollNotifer		__parent;
		int					__notify_fds[2];	// 0-send 1-recv
	#endif

	KSNetEventDispatcher*	dp;

	KSNetSingalNotify		notify_fun;
	void*					notify_tag;
};

BOOL    ks_net_signal_init( KSNetSingal* self, KSNetEventDispatcher* dp, KSNetSingalNotify notify_fun, void* notify_tag );
void    ks_net_signal_uninit( KSNetSingal* self );
void    ks_net_signal( KSNetSingal* self );

KS_DECLS_END

#endif//_KS_INC_NETLIB_H_

